package com.runa.monitor.platinterface.base;

import com.runa.monitor.platinterface.backwork.function.NetStatusCallback;
import com.runa.monitor.platinterface.netservice.connect.Session;
import com.runa.monitor.platinterface.netservice.equipment.DtuPlcService;
import com.runa.monitor.platinterface.netservice.equipment.PlcService;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
 * @author zhuj
 */
public class BaseContainer {

    private static final Logger logger = LoggerFactory.getLogger(BaseContainer.class);

    private static Map<String, Set<DtuPlcService>> dtuPlcServices = new HashMap<>();

    private static ConcurrentMap<String, Session> sessionPool = new ConcurrentHashMap<>();

    private static NetStatusCallback<String> netStatusCallback = null;

    private static Map<String, Consumer> callbackConsumer = new HashMap<>();

    public static Session getSession(String key) {
        return sessionPool.get(key);
    }

    private static Collection<Session> getUsableSession() {
        return sessionPool.values();
    }

    public static void putSession(String key, Session session) {
        if (key != null) {
            sessionPool.put(key, session);
        }
    }

    public static void removeSession(String key) {
        if (key != null) {
            sessionPool.remove(key);
        }
    }

    public static Set<DtuPlcService> getDtu(String dtuId) {
        return dtuPlcServices.get(dtuId);
    }

    public static void putPlcService(PlcService plcService) {
        if (plcService != null) {
            if (plcService instanceof DtuPlcService) {
                Set<DtuPlcService> dps = dtuPlcServices.get(((DtuPlcService) plcService).getDtuID());
                if (dps == null) {
                    dps = new HashSet<>();
                    dps.add((DtuPlcService) plcService);
                    dtuPlcServices.put(((DtuPlcService) plcService).getDtuID(), dps);
                } else {
                    dps.add((DtuPlcService) plcService);
                }
            }
        }
    }

    public static NetStatusCallback<String> netStatusCallback() {
        return netStatusCallback;
    }

    public static void setNetStatusCallback(NetStatusCallback<String> netStatusCallback) {
        if (BaseContainer.netStatusCallback == null) {
            BaseContainer.netStatusCallback = netStatusCallback;
        }
    }

    public static Consumer getCallbackConsumer(String consumer) {
        return callbackConsumer.get(consumer);
    }

    public static Consumer fuzzyGetCallbackConsumer(String fuzzyTag) {
        if (StringUtil.isNullOrEmpty(fuzzyTag)){
            return null;
        }
        for (Map.Entry<String, Consumer> consumerEntry : callbackConsumer.entrySet()) {
            if (fuzzyTag.contains(consumerEntry.getKey())) {
                return consumerEntry.getValue();
            }
        }
        return null;
    }

    /**
     * 异步循环发送请求
     */
    private final static int THREAD_SIZE =1;
    private final static boolean[] SCHEDULER_STATE = new boolean[THREAD_SIZE];

    static {
        for (int i = 0; i < THREAD_SIZE; i++) {
            int I = i;
            SCHEDULER_STATE[i] = true;
            new Thread(() -> {
                while (SCHEDULER_STATE[I]) {
                    for (Session session : BaseContainer.getUsableSession()) {
                        try {
                            session.requesting();
                        } catch (Exception e) {
                            logger.error("Request Scheduler Error: ", e);
                        }
                    }
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException ignored) {}
                }
            },"session-scheduler-"+i).start();
        }
    }

    /**
     * 计量异步处理线程池
     */
    private static Executor netEquExecutor;

    public static void netEquReceiveFunc(Runnable runnable) {
        netEquExecutor.execute(runnable);
    }

    public static void setNetEquExecutor(Executor executor) {
        BaseContainer.netEquExecutor = executor;
    }
}
